package alexAI;

import java.util.ArrayList;

import legacy.TestTree;

public class AI
{
 public static int masterCpt = 0;
 private static int[] score = new int[2];
 private static int[] tmpInt = new int[2];
 
 public AI()
 {
  
 }
 
 
 /**
  * This is a copy of what you can find in the Game class, but this one has less coupling
  * @param board int[][] ; contains the board to evaluate
  * @param isWhite boolean ; wether the player is playing white or not
  * @return score int ; the score for this shnitz
  */
 public static int evalBoard(int[][] board, boolean isWhite)
 {
  int score = 0;
  score = score + evalNbPiecesLeft(board, isWhite);
  score = score + evalPusheeMobility(board, isWhite);
  return score;
 }
 
 
 
 /**
  * This is a copy of what you can find in the Game class, but this one has less coupling
  * @param board int[][] ; contains the board to evaluate
  * @param isWhite boolean ; wether the player is playing white or not
  * @return score int ; the score for this shnitz
  */
 public static int evalMiniBoard(int[][] board, boolean isWhite)//
 {
  int score = 0;
  score = score + evalMiniNbPiecesLeft(board, isWhite);
//  System.out.println("Score de nbPieces: " + evalMiniNbPiecesLeft(board, isWhite));
  score = score + evalMiniPusheeMobility(board, isWhite);
 // System.out.println("Score Pushee mobility: " + evalMiniPusheeMobility(board, isWhite));
  return score;
 }
 
 
 
 /**
  * This is a copy of what you can find in the Game class, but this one has less coupling
  * @param board int[][] ; contains the board to evaluate
  * @param isWhite boolean ; wether the player is playing white or not
  * @return score int ; the score for this shnitz
  */
 public static int evalBoard(int[][] board)
 {
  int score = 0;
//  score = score + evalNbPiecesLeft(board, isWhite);
//  score = score + evalPusheeMobility(board);
  return score;
 }
 
 
 
 
 /**
  * This method will evaluate the amount of pieces left on the board and attribute a score. It will 
  * do the same for the adversary and give the same value to his pieces (negative tho) than his own
  * @param board int[][] ; contains the board to evaluate
  * @param isWhite boolean ; wether the player is playing white or not
  * @return score int ; the score for this shnitz
  */
 public static int evalNbPiecesLeft(int[][] board, boolean isWhite)
 {
  int score = 0;
  
  if (isWhite) // white player
  {
   for (int i = 0 ; i < 8 ; i++)
   {
    for (int j = 0 ; j < 8 ; j++)
    {
     switch (board[i][j])
     {
      case 1: // encountered White Pushee
       // oh yeah we still have a pushee alive! +10 for the score
       score = score + 10;
       break;
       
      case 2: // encountered White Pusher
       score = score + 20;
       break;
      
      case 3: // encountered Black Pushee
       score = score - 10;
       break;
        
      case 4: // encountered Black Pusher
       score = score - 20;
       break;
       
      default:
       break;
     }
    }
   }
  }
  else // playing black
  {
   for (int i = 0 ; i < 8 ; i++)
   {
    for (int j = 0 ; j < 8 ; j++)
    {
     switch (board[i][j])
     {
      case 1: // encountered White Pushee
       score = score - 10;
       break;
      
      case 2: // encountered White Pusher
       score = score - 20;
       break;
      
      case 3: // encountered Black Pushee
       score = score + 10;
       break;

      case 4: // encountered Black Pusher
       score = score + 20;
       break;
       
      default:
       break;
     }
    }
   }
  } 
  return score;
 }
 
 
 
 /**
  * This method will evaluate the amount of pieces left on the board and attribute a score. It will 
  * do the same for the adversary and give the same value to his pieces (negative tho) than his own
  * @param board int[][] ; contains the board to evaluate
  * @param isWhite boolean ; wether the player is playing white or not
  * @return score int ; the score for this shnitz
  */
 public static int evalMiniNbPiecesLeft(int[][] board, boolean isWhite)
 {
  int score = 0;
  
  if (isWhite) // white player
  {
   for (int i = 0 ; i < 4 ; i++)
   {
    for (int j = 0 ; j < 4 ; j++)
    {
     switch (board[i][j])
     {
      case 1: // encountered White Pushee
       // oh yeah we still have a pushee alive! +10 for the score
       score = score + 10;
       break;
       
      case 2: // encountered White Pusher
       score = score + 20;
       break;
      
      case 3: // encountered Black Pushee
       score = score - 10;
       break;
        
      case 4: // encountered Black Pusher
       score = score - 20;
       break;
       
      default:
       break;
     }
    }
   }
  }
  else // playing black
  {
   for (int i = 0 ; i < 4 ; i++)
   {
    for (int j = 0 ; j < 4 ; j++)
    {
     switch (board[i][j])
     {
      case 1: // encountered White Pushee
       score = score - 10;
       break;
      
      case 2: // encountered White Pusher
       score = score - 20;
       break;
      
      case 3: // encountered Black Pushee
       score = score + 10;
       break;

      case 4: // encountered Black Pusher
       score = score + 20;
       break;
       
      default:
       break;
     }
    }
   }
  } 
  return score;
 }
 
 
 
 /**
  * This method examine every Pushee and check how many Pusher are behind it, for every Pusher found
  * the score is incremented by 1. This is justified by the reasonning that a Pushee isn't worth much
  * without Pusher able to interract with. This need to be aggressively optimized, a Pusher behind a
  * pushee in a straight line cannot eat jack shit so it should not have same value as a Black Pusher 
  * in a diagonal position. In the same line, the algorithm should take in account the situation of 
  * the pushee for its adversary (easy implementation)
  * @param board int[][] ; board to examine
  * @param isWhite boolean ; is player White or not
  * @return score int ; the score for this
  */
 public static int evalPusheeMobility(int[][] board, boolean isWhite)
 {
  int score = 0;
  int xLowerBound;
  int xUpperBound;
  
  //GameUtils.printBoard(board);
  
  if (isWhite) // white player
  {
   for (int i = 0 ; i < 8 ; i++)
   {
    for (int j = 0 ; j < 8 ; j++)
    {
     if (board[i][j] == 1) // finding pushee
     {
      xLowerBound = i - 1;
      xUpperBound = i + 1;
      if (i == 0){xLowerBound = 0;}
      if (i == 7){xUpperBound = 7;}
      for (int k = xLowerBound ; k <= xUpperBound ; k++)
      {
       if (board[k][j-1] == 2) // White player will have the Pusher behind him at j-1
       {
        score = score + 1; // + 1 points for every Pusher behind pushee
       }
      }
     }
    }
   }
  }
  else // black player
  {
   for (int i = 0 ; i < 8 ; i++)
   {
    for (int j = 0 ; j < 8 ; j++)
    {
     if (board[i][j] == 3)
     {
      xLowerBound = i - 1;
      xUpperBound = i + 1;
      if (i == 0){xLowerBound = 0;}
      if (i == 7){xUpperBound = 7;}
      for (int k = xLowerBound ; k <= xUpperBound ; k++)
      {
       if (board[k][j+1] == 4) // Black player will have the Pusher behind him at j+1
       {
        score = score + 1; // + 1 points for every Pusher behind pushee
       }
      }
     } 
    }
   }
  } 
  
  return score;
 }
 
 
 
 
 /**
  * This method examine every Pushee and check how many Pusher are behind it, for every Pusher found
  * the score is incremented by 1. This is justified by the reasonning that a Pushee isn't worth much
  * without Pusher able to interract with. This need to be aggressively optimized, a Pusher behind a
  * pushee in a straight line cannot eat jack shit so it should not have same value as a Black Pusher 
  * in a diagonal position. In the same line, the algorithm should take in account the situation of 
  * the pushee for its adversary (easy implementation)
  * @param board int[][] ; board to examine
  * @param isWhite boolean ; is player White or not
  * @return score int ; the score for this
  */
 public static int evalMiniPusheeMobility(int[][] board, boolean isWhite)
 {
  int score = 0;
  int xLowerBound;
  int xUpperBound;
  
  if (isWhite) // white player
  {
   for (int i = 0 ; i < 4 ; i++)
   {
    for (int j = 0 ; j < 4 ; j++)
    {
     if (board[i][j] == 1)
     {
      xLowerBound = i - 1;
      xUpperBound = i + 1;
      if (i == 0){xLowerBound = 0;}
      if (i == 3){xUpperBound = 3;}
      for (int k = xLowerBound ; k <= xUpperBound ; k++)
      {
       if ((j-1) != -1 && board[k][j-1] == 2) // White player will have the Pusher behind him at j-1
       {
        score = score + 1; // + 1 points for every Pusher behind pushee
       }
      }
     }
    }
   }
  }
  else // black player
  {
   for (int i = 0 ; i < 4 ; i++)
   {
    for (int j = 0 ; j < 4 ; j++)
    {
     if (board[i][j] == 3)
     {
      xLowerBound = i - 1;
      xUpperBound = i + 1;
      if (i == 0){xLowerBound = 0;}
      if (i == 3){xUpperBound = 3;}
      for (int k = xLowerBound ; k <= xUpperBound ; k++)
      {
       if (board[k][j+1] == 4) // Black player will have the Pusher behind him at j+1
       {
        score = score + 1; // + 1 points for every Pusher behind pushee
       }
      }
     } 
    }
   }
  } 
  
  return score;
 }
 

 
 public static int[] miniMaxAB(int[][] currentBoard, boolean player, int depth, int maxDepth, boolean whoToMax, int alpha, int beta)
 {
  if (depth == maxDepth)
  {
   tmpInt[0] = evalBoard(currentBoard, player);
   System.out.println("For this board: ");
   GameUtils.printBoard(currentBoard);
   System.out.println("The score is: " + tmpInt[0]);
   //tmpInt[1] = currentNode.getUniqueID();
   masterCpt++;
   return tmpInt;
  }
  
  if (whoToMax == player) // Will execute if it's the MAX player turn to play
  {
   int[] alphaLocal = new int[2];
   alphaLocal[0] = -10000;
   
   ArrayList<int[][]> moves = GameUtils.getAllValidMoves(currentBoard, player);
   ArrayList<int[][]> boards = GameUtils.convertMovesToArray(currentBoard, moves);
   for (int i = 0; i < boards.size(); i++)
   {
    int[][] newBoard = GameUtils.copyBoard(boards.get(i));
    //GameUtils.printBoard(newBoard);

    score = miniMaxAB(newBoard, false, depth+1, maxDepth, whoToMax, Math.max(alpha, alphaLocal[0]), beta);
    alphaLocal[0] = Math.max(alphaLocal[0], score[0]);
    
    if (alphaLocal[0] > beta)
    {
     //alphaLocal[1] = currentNode.getUniqueID();
     return alphaLocal;
    }
    if (alphaLocal[0] == score[0])
    {
     //alphaLocal[1] = newNode.getUniqueID();
    }
    
    //System.out.println("In MAX for node with uniqueID: " + newNode.getUniqueID()+ " score is: " + score[0] + " alphaLocal is: " + alphaLocal[0] + " alpha is: " + alpha + " beta is: " + beta);
    System.out.println("In MAX for node score is: " + score[0] + " alphaLocal is: " + alphaLocal[0] + " alpha is: " + alpha + " beta is: " + beta);
    System.out.println("*** MaxScore is now at: " + alphaLocal[0]);
   }
   return alphaLocal;
  }
  else // Will execute if it's the MIN player turn to play
  {
   int[] betaLocal = new int[2];
   betaLocal[0] = 10000;
   
   ArrayList<int[][]> moves = GameUtils.getAllValidMoves(currentBoard, player);
   ArrayList<int[][]> boards = GameUtils.convertMovesToArray(currentBoard, moves);
   for (int i = 0; i < boards.size(); i++)
   {
    int[][] newBoard = GameUtils.copyBoard(boards.get(i));
    //GameUtils.printBoard(newBoard);

    score = miniMaxAB(newBoard, true, depth+1, maxDepth, whoToMax, alpha, Math.min(betaLocal[0], beta));
    betaLocal[0] = Math.min(betaLocal[0], score[0]);
    if (betaLocal[0] < alpha)
    {
    // betaLocal[1] = currentNode.getUniqueID();
     return betaLocal;
    }
    if (betaLocal[0] == score[0])
    {
    // betaLocal[1] = newNode.getUniqueID();
    }
   // System.out.println("In MIN for node with uniqueID: " + newNode.getUniqueID()+ " score is: " + score[0] + " betaLocal is: " + betaLocal[0] + " beta is: " + beta + " alpha is: " + alpha);
    System.out.println("In MIN for node score is: " + score[0] + " betaLocal is: " + betaLocal[0] + " beta is: " + beta + " alpha is: " + alpha);
    System.out.println("*** MinScore is now at: " + betaLocal[0]);
   }
   return betaLocal;
  }
 }
 
 
 //(int[][] currentBoard, boolean player, int depth, int maxDepth, boolean whoToMax, int alpha, int beta)
 public static void main(String[] args) {
	 Game game = new Game();
	 miniMaxAB(game.getBoard(), true, 0, 4, true, -10000, 10000);
 }
 
 
 
 /*
 
 
 public static int[] miniMaxAB(TestTree currentNode, boolean player, int depth, int maxDepth, boolean whoToMax, int alpha, int beta)
 {
  if (depth == maxDepth)
  {
   tmpInt[0] = currentNode.getScore();
   tmpInt[1] = currentNode.getUniqueID();
   masterCpt++;
   return tmpInt;
  }
  
  if (whoToMax == player) // Will execute if it's the MAX player turn to play
  {
   int[] alphaLocal = new int[2];
   alphaLocal[0] = -10000;
   
   ArrayList<TestTree> childrenList = currentNode.getChildren();
   for (int i = 0; i < childrenList.size(); i++)
   {
    TestTree newNode = childrenList.get(i);
    
    score = miniMaxAB(newNode, false, depth+1, maxDepth, whoToMax, Math.max(alpha, alphaLocal[0]), beta);
    alphaLocal[0] = Math.max(alphaLocal[0], score[0]);
    
    if (alphaLocal[0] > beta)
    {
     alphaLocal[1] = currentNode.getUniqueID();
     return alphaLocal;
    }
    if (alphaLocal[0] == score[0])
    {
     alphaLocal[1] = newNode.getUniqueID();
    }
    
    System.out.println("In MAX for node with uniqueID: " + newNode.getUniqueID()+ " score is: " + score[0] + " alphaLocal is: " + alphaLocal[0] + " alpha is: " + alpha + " beta is: " + beta);
    System.out.println("*** MaxScore is now at: " + alphaLocal[0]);
   }
   return alphaLocal;
  }
  else // Will execute if it's the MIN player turn to play
  {
   int[] betaLocal = new int[2];
   betaLocal[0] = 10000;
   
   ArrayList<TestTree> childrenList = currentNode.getChildren();
   for (int i = 0; i < childrenList.size(); i++)
   {
    TestTree newNode = childrenList.get(i);
    
    score = miniMaxAB(newNode, true, depth+1, maxDepth, whoToMax, alpha, Math.min(betaLocal[0], beta));
    betaLocal[0] = Math.min(betaLocal[0], score[0]);
    if (betaLocal[0] < alpha)
    {
     betaLocal[1] = currentNode.getUniqueID();
     return betaLocal;
    }
    if (betaLocal[0] == score[0])
    {
     betaLocal[1] = newNode.getUniqueID();
    }
    System.out.println("In MIN for node with uniqueID: " + newNode.getUniqueID()+ " score is: " + score[0] + " betaLocal is: " + betaLocal[0] + " beta is: " + beta + " alpha is: " + alpha);
    System.out.println("*** MinScore is now at: " + betaLocal[0]);
   }
   return betaLocal;
  }
 }
 
 */
}
